﻿using System;
using System.Collections.Generic;
using System.IO;

namespace PokemonBattle.PokemonData
{
    [Serializable]
    public class PokemonData : DataStream
    {
        #region props

        public List<int> AfterEvolution { get; set; }
        public int BeforeEvolution { get; set; }
        public EggGroup EggGroup1 { get; set; }
        public EggGroup EggGroup2 { get; set; }
        public PokemonGenderRestriction GenderRestriction { get; set; }
        public int Identity { get; set; }
        public Item ItemRestriction { get; set; }
        public List<MoveLearnData> Moves { get; set; }
        public string NameBase { get; set; }
        public int Number { get; set; }
        public Trait Trait1 { get; set; }
        public Trait Trait2 { get; set; }
        public string Type1 { get; set; }
        public string Type2 { get; set; }
        public double Weight { get; set; }
        public int UsageCount { get; set; }

        #endregion

        #region 6D

        public Base6D Bv { get; set; }

        public byte HPBase
        {
            get { return (byte)Bv.Hp; }
            set { Bv.Hp = value; }
        }
        public byte AttackBase
        {
            get { return (byte)Bv.Atk; }
            set { Bv.Atk = value; }
        }
        public byte DefenceBase
        {
            get { return (byte)Bv.Def; }
            set { Bv.Def = value; }
        }
        public byte SpAttackBase
        {
            get { return (byte)Bv.SpAtk; }
            set { Bv.SpAtk = value; }
        }
        public byte SpDefenceBase
        {
            get { return (byte)Bv.SpDef; }
            set { Bv.SpDef = value; }
        }
        public byte SpeedBase
        {
            get { return (byte)Bv.Speed; }
            set { Bv.Speed = value; }
        }

        #endregion

        #region Image

        public long FrontImage { get; set; }
        public long FrontImageF { get; set; }
        public long BackImage { get; set; }
        public long BackImageF { get; set; }
        public long Icon { get; set; }
        public long Frame { get; set; }
        public long FrameF { get; set; }

        #endregion

        public PokemonData()
        {
            Moves = new List<MoveLearnData>();
            AfterEvolution = new List<int>();
            Bv = new Base6D(0);
            Type1 = "";
            Type2 = "";
        }

        public MoveLearnData GetMove(string moveName)
        {
            return Moves.Find((move) => move.MoveName == moveName);
        }

        #region abstract

        public override void Load(Stream input)
        {
            BinaryReader reader = new BinaryReader(input);

            this.Trait1 = (Trait)reader.ReadInt32();
            this.Trait2 = (Trait)reader.ReadInt32();
            this.EggGroup1 = (EggGroup)reader.ReadInt32();
            this.EggGroup2 = (EggGroup)reader.ReadInt32();
            this.GenderRestriction = (PokemonGenderRestriction)reader.ReadInt32();
            this.Identity = reader.ReadInt32();
            this.NameBase = reader.ReadString();
            this.Number = reader.ReadInt32();
            this.Weight = reader.ReadDouble();
            this.HPBase = reader.ReadByte();
            this.AttackBase = reader.ReadByte();
            this.DefenceBase = reader.ReadByte();
            this.SpeedBase = reader.ReadByte();
            this.SpAttackBase = reader.ReadByte();
            this.SpDefenceBase = reader.ReadByte();
            this.Type1 = reader.ReadString();
            this.Type2 = reader.ReadString();
            this.BeforeEvolution = reader.ReadInt32();
            this.FrontImage = reader.ReadInt64();
            this.FrontImageF = reader.ReadInt64();
            this.BackImage = reader.ReadInt64();
            this.BackImageF = reader.ReadInt64();
            this.Icon = reader.ReadInt64();
            this.Frame = reader.ReadInt64();
            this.FrameF = reader.ReadInt64();

            int count = reader.ReadInt32();
            for (int i = 0; i < count; i++)
            {
                this.AfterEvolution.Add(reader.ReadInt32());
            }
            count = reader.ReadInt32();
            for (int i = 0; i < count; i++)
            {
                var move = FromStream<MoveLearnData>(input);
                this.Moves.Add(move);
            }

            this.ItemRestriction = (Item)reader.ReadInt32();
        }

        public override void Save(Stream output)
        {
            BinaryWriter writer = new BinaryWriter(output);

            writer.Write((int)this.Trait1);
            writer.Write((int)this.Trait2);
            writer.Write((int)this.EggGroup1);
            writer.Write((int)this.EggGroup2);
            writer.Write((int)this.GenderRestriction);
            writer.Write(this.Identity);
            writer.Write(this.NameBase);
            writer.Write(this.Number);
            writer.Write(this.Weight);
            writer.Write(this.HPBase);
            writer.Write(this.AttackBase);
            writer.Write(this.DefenceBase);
            writer.Write(this.SpeedBase);
            writer.Write(this.SpAttackBase);
            writer.Write(this.SpDefenceBase);
            writer.Write(this.Type1);
            writer.Write(this.Type2);
            writer.Write(this.BeforeEvolution);
            writer.Write(this.FrontImage);
            writer.Write(this.FrontImageF);
            writer.Write(this.BackImage);
            writer.Write(this.BackImageF);
            writer.Write(this.Icon);
            writer.Write(this.Frame);
            writer.Write(this.FrameF);
            writer.Write(this.AfterEvolution.Count);

            foreach (int identity in AfterEvolution)
            {
                writer.Write(identity);
            }
            writer.Write(Moves.Count);
            foreach (MoveLearnData move in Moves)
            {
                move.Save(output);
            }

            writer.Write((int)ItemRestriction);
        }

        #endregion

        public static PokemonData FromStream(Stream input)
        {
            return FromStream<PokemonData>(input);
        }
    }
}
